unit oPedestriansManager;

{
	created   7.3.2010
	author    Michal Varga
	purpose   holds and manages the Pedestrian Types

	edit list:

        comment list:
                  8.3.2010 Michal Varga
                    TPedestrianType declared as nested class in manager
                    removing of pedestrian data can be done after creating of arrival manager
                    because of the reference checking
        to-do list:
                  8.3. Michal Varga
                    overload assignement operator in TPedestrianType
                  10.3. Michal Varga
                    inherited master in constructor
}

interface

uses
  oManager, Classes, Generics.Collections, oProcessItem,
  SysUtils, XMLDoc, XMLIntf, oProcessObjects, oVector, oMathematic;

type
  EPedestrianManager = class(Exception)
  end;

  ENotValidPedestrianType = class(EPedestrianManager)
  end;

  EPedestrianNotExists = class(EPedestrianManager)
  end;

  EPedestrianAlreadyExists = class(EPedestrianManager)
  end;

  TPedestrianManager = class(TManager)
    public
      type
        TPedestrianType = class(TProcessable)
          strict private
            aName: String;
            aCrowdTightning: Real;
            aGainTightning: Real;
            aBarierTightning: Real;
            aDiameter: Real;
            aAvgVelocity: Real;
            aMaxVelocity: TFloat;
            aMaxAcceleration: TFloat;
            aView: Real;
            aPedType: Integer;
          public
            property Name: String read aName;
            property CrowdTightning: Real read aCrowdTightning;
            property GainTightning: Real read aGainTightning;
            property BarierTightning: Real read aBarierTightning;
            property Diameter: Real read aDiameter;
            property AvgVelocity: Real read aAvgVelocity;
            property MaxVelocity: TFloat read aMaxVelocity;
            property MaxAcceleration: TFloat read aMaxAcceleration;
            property View: Real read aView;
          private
            constructor Create(paName: String;
                           paCrowdTightning: Real;
                           paGainTightning: Real;
                           paBarierTightning: Real;
                           paDiameter: Real;
                           paAvgVelocity: Real;
                           paMaxVelocity: Real;
                           paMaxAcceleration: Real;
                           paView: Real); overload;
            constructor Create; overload;
            constructor Create(paData: TPedestrianData); overload;
            procedure Assign(rhs: TPedestrianData);
            procedure Save(var paWhere: IXMLNode);
            procedure Load(paFrom: IXMLNode);
            //class operator Implicit(paPedData: TPedestrianData):TPedestrianType
        end;
    private
      aPedestrians: TList<TPedestrianType>;
      function search(paName: String): TPedestrianType;
      procedure resetList;
      procedure unload;
      function exists(paName: String): boolean;
    public
      property Pedestrians: TList<TPedestrianType> read aPedestrians;
      constructor Create(paMaster: TManager);
      destructor Destroy; override;
      function ProcessObject(paItem: TProcessItem):TProcessItem; override; final;
  end;

implementation

uses
  oProcessObjectConstants;

resourcestring ePedManNotValidType = 'not a valid processing type';
resourcestring ePedManNotValidConstant = 'not a valid constant';
resourcestring ePedManFoundDuplicity = 'entity already exists';
resourcestring ePedManPedestrianNotFound = 'entity not found';

{ TPedestrianManager }

constructor TPedestrianManager.Create(paMaster: TManager);
begin
  aMaster := paMaster;
  aPedestrians := TList<TPedestrianType>.Create;
end;

destructor TPedestrianManager.Destroy;
var
  pedestrian: TPedestrianType;
begin
  for pedestrian in Pedestrians do
    pedestrian.Free;
  aPedestrians.Free;
  inherited;
end;

function TPedestrianManager.exists(paName: String): boolean;
var
  pedestrian: TPedestrianType;
begin
  result := false;
  for pedestrian in Pedestrians do
    if pedestrian.Name = paName then
    begin
      result := true;
      break;
    end;

end;

function TPedestrianManager.ProcessObject(paItem: TProcessItem): TProcessItem;
var
  pedestrian: TPedestrianType;
  node: IXMLNode;
  strings : TStringList;

begin
  result := nil;
  case paItem.Code of

    PO_PEDMAN_INSERT:
    begin
      try
        if not(paItem.Data is TPedestrianData) then raise ENotValidPedestrianType.Create(ePedManNotValidType);
        if exists((paItem.Data as TPedestrianData).NameData) then raise EPedestrianAlreadyExists.Create(ePedManFoundDuplicity);
        Pedestrians.Add(TPedestrianType.Create(paItem.Data as TPedestrianData));
        Master.ProcessObject(TProcessItem.create(PO_TREE_REFRESH_PEDEST_SUBLAYER, nil));
        Master.ProcessObject(TProcessItem.create(PO_PROJECT_SAVE_PEDESTRIANS, nil));
        paItem.Free;
        result := nil;
      except
        on E:ENotValidPedestrianType do raise EPedestrianManager.Create(ePedManNotValidType);
        on E:EPedestrianManager do result := TProcessItem.create(PO_FAILURE,nil);
      end;
    end;

    PO_PEDMAN_REMOVE:
    begin
      try
        if not(paItem.Data is TString) then raise ENotValidPedestrianType.Create(ePedManNotValidType);
        if exists((paItem.Data as TString).String_)
          then begin
            pedestrian := search((paItem.Data as TString).String_);
            Pedestrians.Extract(pedestrian).Free;
          end;
        paItem.Data.Free;
        paItem.Free;
        result := nil;
      except
        on E:ENotValidPedestrianType do raise EPedestrianManager.Create(ePedManNotValidType);
      end;
    end;

    PO_PEDMAN_GET_NAMES : begin
      strings := TStringList.Create;
      for pedestrian in aPedestrians do
        strings.Add(pedestrian.Name);
      Result := TProcessItem.create(PO_SUCCESS, TProcessingStrings.Create(strings));
      paItem.Data.Free;
      paItem.Free;
    end;

    PO_PEDMAN_EDIT:
    begin
      try
        if not(paItem.Data is TPedestrianData) then raise ENotValidPedestrianType.Create(ePedManNotValidType);
        pedestrian := search((paItem.Data as TPedestrianData).NameData);
        if pedestrian = nil then raise EPedestrianNotExists.Create('');
        pedestrian.Assign((paItem.Data as TPedestrianData));
        Master.ProcessObject(TProcessItem.create(PO_PROJECT_SAVE_PEDESTRIANS, nil));
        paItem.Free;
        result := nil;
      except
        on E:ENotValidPedestrianType do raise EPedestrianManager.Create(ePedManNotValidType);
        on E:EPedestrianNotExists do raise EPedestrianManager.Create(ePedManPedestrianNotFound);
      end;
    end;

    PO_PEDMAN_SAVE:
    begin
        try
        if not(paItem.Data is TProcessingXML) then raise ENotValidPedestrianType.Create(ePedManNotValidType);
        node := ((paItem.Data) as TProcessingXML).Node;
        for pedestrian in aPedestrians do pedestrian.Save(node);
        result := TProcessItem.create(PO_SUCCESS, TProcessingXML.Create(node));
        paItem.Data.Free;
        paItem.Free;
      except
        on E:ENotValidPedestrianType do raise EPedestrianManager.Create(ePedManNotValidType);
      end;
    end;

    PO_PEDMAN_LOAD:
    begin
      try
        if not(paItem.Data is TProcessingXML) then raise ENotValidPedestrianType.Create(ePedManNotValidType);

        resetList;
        node := (paItem.Data as TProcessingXML).Node.ChildNodes.First;
        while node <> nil do
        begin
          pedestrian := TPedestrianType.Create;
          pedestrian.Load(node);
          aPedestrians.Add(pedestrian);
          node := node.NextSibling;
        end;
        paItem.Data.Free;
        paItem.Free;
        result := nil;
      except
        on E:ENotValidPedestrianType do raise EPedestrianManager.Create(ePedManNotValidType);
        //on E:EPedestrianManager do result := TProcessItem.create(PO_FAILURE,nil);
      end;
    end;

    PO_PEDMAN_GET_PEDSTRIAN:
    begin
      try
        if not(paItem.Data is TString) then raise ENotValidPedestrianType.Create(ePedManNotValidType);
        pedestrian := search((paItem.Data As TString).String_);
        if pedestrian = nil then raise EPedestrianNotExists(ePedManPedestrianNotFound);
        paItem.Data.Free;
        paItem.Free;
        Result := TProcessItem.create(PO_SUCCESS,TProcessingPedestrian.create(pedestrian));
      except
        Result := TProcessItem.create(PO_FAILURE,nil);
      end;
    end;

    PO_PEDMAN_EXISTS:
    begin
      try
        if not(paItem.Data is TString) then raise ENotValidPedestrianType.Create(ePedManNotValidType);
        pedestrian := search((paItem.Data as TString).String_);
        if pedestrian <> nil
          then Result := TProcessItem.create(PO_SUCCESS,pedestrian)
          else Result := TProcessItem.create(PO_FAILURE,nil);
        paItem.Data.Free;
        paItem.Free;
      except
        Result := TProcessItem.create(PO_FAILURE,nil);
      end;
    end;

    PO_PEDMAN_UNLOAD:
    begin
      paItem.Free;
      unload;
      Result := nil;
    end;

  end;
end;

procedure TPedestrianManager.resetList;
var
  pedestrian: TPedestrianType;
begin
  for pedestrian in aPedestrians do pedestrian.Free;
  aPedestrians.Free;
  aPedestrians := TList<TPedestrianType>.Create;
end;

function TPedestrianManager.search(paName: String): TPedestrianType;
var
  pedestrian: TPedestrianType;
begin
  for pedestrian in Pedestrians do
    if pedestrian.Name = paName then
    begin
      result := pedestrian;
      exit;
    end;
  result := nil;
end;

procedure TPedestrianManager.unload;
var
  pedestrian: TPedestrianType;
begin
  for pedestrian in aPedestrians do pedestrian.Free;
  aPedestrians.Clear;
end;

{ TPedestrianManager.TPedestrianType }

constructor TPedestrianManager.TPedestrianType.Create(paName: String;
  paCrowdTightning: Real; paGainTightning: Real; paBarierTightning: Real;
  paDiameter, paAvgVelocity, paMaxVelocity, paMaxAcceleration,
  paView: Real);
begin
  inherited create;
  aName := paName;
  aCrowdTightning := paCrowdTightning;
  aGainTightning := paGainTightning;
  aBarierTightning := paBarierTightning;
  aDiameter := paDiameter;
  aAvgVelocity := paAvgVelocity;
  aMaxVelocity := paMaxVelocity;
  aMaxAcceleration := paMaxAcceleration;
  aView := paView;
end;

constructor TPedestrianManager.TPedestrianType.Create;
begin
  inherited create;
  aName := '';
  aCrowdTightning := 0;
  aGainTightning := 0;
  aBarierTightning := 0;
  aDiameter := 0;
  aAvgVelocity := 0;
  aMaxVelocity := 0;
  aMaxAcceleration := 0;
  aView := 0;
end;

procedure TPedestrianManager.TPedestrianType.Assign(rhs: TPedestrianData);
begin
  with rhs do
  begin
    aCrowdTightning := CrowdTightningData;
    aGainTightning := GainTightningData;
    aBarierTightning := BarierTightningData;
    aDiameter := DiameterData;
    aAvgVelocity := AvgVelocityData;
    aMaxVelocity := MaxVelocityData;
    aMaxAcceleration := MaxAccelerationData;
    aView := ViewData;
  end;
end;

constructor TPedestrianManager.TPedestrianType.Create(paData: TPedestrianData);
begin
  inherited create;
  with paData do
  begin
    aName := NameData;
    aCrowdTightning := CrowdTightningData;
    aGainTightning := GainTightningData;
    aBarierTightning := BarierTightningData;
    aDiameter := DiameterData;
    aAvgVelocity := AvgVelocityData;
    aMaxVelocity := MaxVelocityData;
    aMaxAcceleration := MaxAccelerationData;
    aView := ViewData;
  end;
end;

procedure TPedestrianManager.TPedestrianType.Load(paFrom: IXMLNode);
var PedTypeNode,PedTypeAttribute: IXMLNode;
begin
  PedTypeNode := paFrom;
  if PedTypeNode.HasAttribute('name') then aName := PedTypeNode.Attributes['name'];
  //crowd tightning
  PedTypeAttribute := PedTypeNode.ChildNodes.FindNode('CrowdTightning');
  if PedTypeAttribute.HasAttribute('value') then aCrowdTightning := PedTypeAttribute.Attributes['value'];
  //gain tightning
  PedTypeAttribute := PedTypeNode.ChildNodes.FindNode('GainTightning');
  if (PedTypeAttribute <> nil) and (PedTypeAttribute.HasAttribute('value'))
    then aGainTightning := PedTypeAttribute.Attributes['value']
    else aGainTightning := 4;
  //barier tightning
  PedTypeAttribute := PedTypeNode.ChildNodes.FindNode('BarierTightning');
  if (PedTypeAttribute <> nil) and (PedTypeAttribute.HasAttribute('value'))
    then aBarierTightning := PedTypeAttribute.Attributes['value']
    else aBarierTightning := -1;
  //diameter
  PedTypeAttribute := PedTypeNode.ChildNodes.FindNode('Diameter');
  if PedTypeAttribute.HasAttribute('value') then aDiameter := PedTypeAttribute.Attributes['value'];
  //view
  PedTypeAttribute := PedTypeNode.ChildNodes.FindNode('View');
  if PedTypeAttribute.HasAttribute('value') then aView := PedTypeAttribute.Attributes['value'];
  //average velocity
  PedTypeAttribute := PedTypeNode.ChildNodes.FindNode('AvgVelocity');
  if PedTypeAttribute.HasAttribute('value') then aAvgVelocity := PedTypeAttribute.Attributes['value'];
  //maximal velocity
  PedTypeAttribute := PedTypeNode.ChildNodes.FindNode('MaxVelocity');
  if PedTypeAttribute.HasAttribute('value') then aMaxVelocity := PedTypeAttribute.Attributes['value'];
  //maximal acceleration
  PedTypeAttribute := PedTypeNode.ChildNodes.FindNode('MaxAcceleration');
  if PedTypeAttribute.HasAttribute('value') then aMaxAcceleration := PedTypeAttribute.Attributes['value'];
end;

procedure TPedestrianManager.TPedestrianType.Save(var paWhere: IXMLNode);
var PedTypeNode,PedTypeAttribute: IXMLNode;
begin
  PedTypeNode := paWhere.AddChild('PedestrianType');
  PedTypeNode.Attributes['name'] := Name;
  PedTypeAttribute := PedTypeNode.AddChild('CrowdTightning');
  PedTypeAttribute.Attributes['value'] := CrowdTightning;
  PedTypeAttribute := PedTypeNode.AddChild('GainTightning');
  PedTypeAttribute.Attributes['value'] := GainTightning;
  PedTypeAttribute := PedTypeNode.AddChild('BarierTightning');
  PedTypeAttribute.Attributes['value'] := BarierTightning;
  PedTypeAttribute := PedTypeNode.AddChild('Diameter');
  PedTypeAttribute.Attributes['value'] := Diameter;
  PedTypeAttribute := PedTypeNode.AddChild('View');
  PedTypeAttribute.Attributes['value'] := View;
  PedTypeAttribute := PedTypeNode.AddChild('AvgVelocity');
  PedTypeAttribute.Attributes['value'] := AvgVelocity;
  PedTypeAttribute := PedTypeNode.AddChild('MaxVelocity');
  PedTypeAttribute.Attributes['value'] := MaxVelocity;
  PedTypeAttribute := PedTypeNode.AddChild('MaxAcceleration');
  PedTypeAttribute.Attributes['value'] := MaxAcceleration;
end;

end.
